package org.gfix.parser;

import org.gfix.parser.FixHandler;
import org.gfix.parser.FixParseFault;
import org.gfix.parser.FixParser;
import org.gfix.parser.ValidatingValidator;
import org.hamcrest.Matchers;
import org.jmock.Expectations;
import org.junit.Test;


public class ValidatingFixParserTest extends BaseParserTest {

	
	@Override
	protected FixParser getParser()
	{
		return new FixParser(new ValidatingValidator.Factory());
	}
	
	
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageMustStartWith8Equals() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "1=hello", new Expectations()
		{{
		    oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(1)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("hello"))
		    		)));
			oneOf(handler).newTag(with(1), with("hello"));
		}});
	}
	
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageMustStartWith8ContentsMustBeSupplied() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=\001", new Expectations()
		{{
		    oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(8)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo(""))
		    		)));
			oneOf(handler).newTag(with(8), with(""));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageMustContainJustOne8Equals() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=123\00135=X\0018=FIX.4.2", new Expectations()
		{{
		    oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(8)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("FIX.4.2"))
		    		)));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("123"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageMustStartWith8ContentsMustBeFIXXXXX() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=LOST\001", new Expectations()
		{{
		    oneOf(handler).warning((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.WARNING)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(8)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("LOST"))
		    		)));
			oneOf(handler).newTag(with(8), with("LOST"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageSecondTagMustBe9() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0011=hello", new Expectations()
		{{
		    oneOf(handler).warning((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.WARNING)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(1)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("hello"))
		    		)));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(1), with("hello"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageSecondTagMustBe9AndBeANumber() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=hello", new Expectations()
		{{
		    oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(9)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("hello"))
		    		)));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("hello"));
		}});
	}
	
	@Test
	public void testMessageSecondTagMustBe9AndBeAParsableNumber() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=123", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("123"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void test9ShouldBesuppliedOnlyOnce() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=123\00135=X\0019=456", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("123"));
			oneOf(handler).newTag(with(35), with("X"));
			 oneOf(handler).error((FixParseFault)with(
			    		Matchers.allOf(
			    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
			    				Matchers.hasProperty("tag", Matchers.equalTo(9)),
			    				Matchers.hasProperty("tagContent", Matchers.equalTo("456"))
			    		)));
			 oneOf(handler).newTag(with(9), with("456"));
		}});
	}
	
////"8=FIX.4.2\0019=12\00135=X\001108=30\00110=049\001"
	@Test
	@SuppressWarnings("unchecked")
	public void testMessageThirdTagMustBe35() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\0013=X\001", new Expectations()
		{{
			oneOf(handler).warning((FixParseFault)with(
	    		Matchers.allOf(
	    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.WARNING)),
	    				Matchers.hasProperty("tag", Matchers.equalTo(3)),
	    				Matchers.hasProperty("tagContent", Matchers.equalTo("X"))
	    		)));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(3), with("X"));
		}});
	}
	
	
	@Test
	public void testMessageThirdTagMustBe35Correct() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testCheckSum10Incorrect() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=30\00110=089\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(10)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("089"))
		    		)));
			oneOf(handler).newTag(with(10), with("089"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testCheckSum10IncorrectDueToMessage() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=31\00110=049\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("31"));
			oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(10)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("049"))
		    		)));
			oneOf(handler).newTag(with(10), with("049"));
		}});
	}
	
	@Test
	public void testCheckSum10() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=30\00110=049\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).newTag(with(10), with("049"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testCheckSum10ShouldBeNumber() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=30\00110=WORLD\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(10)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("WORLD"))
		    		)));
			oneOf(handler).newTag(with(10), with("WORLD"));
		}});
	}
	
	@Test
	@SuppressWarnings("unchecked")
	public void testCheckOn10LengthsShouldBeChecked() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=15\00135=X\001108=30\00110=049\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("15"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).error((FixParseFault)with(
		    		Matchers.allOf(
		    				Matchers.hasProperty("serverity", Matchers.equalTo(FixParseFault.Serverity.ERROR)),
		    				Matchers.hasProperty("tag", Matchers.equalTo(10)),
		    				Matchers.hasProperty("tagContent", Matchers.equalTo("049"))
		    		)));
			oneOf(handler).newTag(with(10), with("049"));
		}});
	}
	
	@Test
	public void testReset() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=30\00110=049\0018=FIX.4.2\0019=12\00135=X\001108=30\00110=049\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).newTag(with(10), with("049"));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).newTag(with(10), with("049"));
		}});
	}
	
	@Test
	public void testWhiteSpaceBetweenMessages() throws Exception
	{
		final FixHandler handler = context.mock(FixHandler.class);			
		runTest(handler, "8=FIX.4.2\0019=12\00135=X\001108=30\00110=049\001\n\n\n\t\t\t8=FIX.4.2\0019=12\00135=X\001108=30\00110=049\001", new Expectations()
		{{
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).newTag(with(10), with("049"));
			oneOf(handler).newTag(with(8), with("FIX.4.2"));
			oneOf(handler).newTag(with(9), with("12"));
			oneOf(handler).newTag(with(35), with("X"));
			oneOf(handler).newTag(with(108), with("30"));
			oneOf(handler).newTag(with(10), with("049"));
		}});

	}
}
